#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>

#include <MemoriaCompartida.h>
#include <FifoEscritura.h>
#include <FifoLectura.h>
#include <BaseException.h>
#include <Semaforo.h>
#include <SignalHandler.h>
#include <ExitHandler.h>
#include <Jefe.h>
#include <Logger.h>
#include <Utils.h>
#include <ConfigurationFile.h>

using namespace std;

int main (int argc, char* argv[])
{
	Jefe* jefe = NULL;
	Logger* log = Logger::getInstance();
	
	// Event handler para evento de salida
	ExitHandler exitHandler;
	
	// Se registran los event handlers
	SignalHandler::getInstance()->registrarHandler ( SIGINT, &exitHandler);
	SignalHandler::getInstance()->registrarHandler ( SIGQUIT, &exitHandler );
	SignalHandler::getInstance()->registrarHandler ( SIGTERM, &exitHandler );
	
	try
	{
		jefe = new Jefe();
		std::string strPID = Utils::convertIntToStr(getpid());
		
		log->info("JEFE >> Proceso Jefe de Estacion iniciado >> Jefe de estacion PID: " + strPID);
		
		int cantClientesAtendidos = 0;
		int cantClientes = Utils::convertSrtToInt(ConfigurationFile::getProperty(Properties::CANT_CLIENTES));
		
		// Creo receptores para procesos cliente y playero
		jefe->crearReceptorClientes();
		jefe->crearReceptorPlayeros();
		
		cout << "PID Jefe:" << getpid() << endl;
		while(!exitHandler.getGracefulQuit() && cantClientesAtendidos < cantClientes)
		{
			log->info("JEFE >> Esperando atender a algun cliente en la cola de recepcion");
			
			jefe->recibirCliente();
			
			log->info("JEFE >> Nuevo cliente recibido >> Buscando playero libre");
			
			if(jefe->hayPlayerosLibres())
			{
				log->info("JEFE >> Playero libre encontrado >> Atendiendo a cliente");
				jefe->atenderCliente();
			}
			else
			{
				log->info("JEFE >> No se encontraron playeros libres >> Despidiendo a cliente");
				jefe->retirarCliente();
			}
			cantClientesAtendidos++;
		}
	}
	catch(BaseException& e)
	{
		if(e.getCode() == EINTR)
			log->info("JEFE >> Se recibio senal de salida");
		else
			log->error(e.what());
	}
	
	if(jefe != NULL)
	{
		log->info("JEFE >> Cerrando estacion");
		jefe->cerrarEstacion();
		delete jefe;
	}
	
	log->info("JEFE >> Finalizando");
	
	// Libero recursos
	SignalHandler::destruir ();
	Logger::destroy();
	
	return 0;
}